/*
 * C5.2.5.c
 *
 *  Created on: 2013/01/16
 *      Author: xun
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rule_info.h"
#include "core.h"
#include "trace.h"
#include "TraceAst.h"

static const PSZ RuleID = "C5.2.5";

//TODO
static const PSZ MESSAGE_ENG = "";
static const PSZ MESSAGE_JPN = "switch文に終了default節がない。";
static const PSZ MESSAGE_CHS = "";

static const U2 RANK = MSG_RANK_ERR;

static PRULEOUT pRuleHead;
static PRULEOUT pRuleTail;

static INT RuleCheck(U2 kind, AST index, U4 event, AST* pCodeScp);

/******************************************************************
 * main logic
 *******************************************************************/
static S4 RuleMain(U2 kind, AST index, U4 event) {
	INT result = RULE_RESULT_OK;
	PRULEOUT newNode = NULL;
	PRULEOUT tmpNode = NULL;
	PRULEOUT tmpNode1 = NULL;

	AST codeScp = 0;

	//TODO
	result = RuleCheck(kind, index, event, &codeScp);

	if (result == RULE_RESULT_OK) {
		return EXIT_SUCCESS;
	}

	/*re-checked?*/
	tmpNode = pRuleHead;
	while (tmpNode != NULL ) {
		if (tmpNode->indexInfo == index) {
			if (result > RULE_RESULT_OK) {
				result = RULE_RESULT_OK;
			} else {
				if (tmpNode == pRuleHead) {
					pRuleHead = pRuleHead->next;
					free(tmpNode);
				} else if (tmpNode == pRuleTail) {
					tmpNode1->next = NULL;
					pRuleTail = tmpNode1;
					free(tmpNode);
				} else {
					tmpNode1->next = tmpNode->next;
					free(tmpNode);
				}
			}
			break;
		}
		tmpNode1 = tmpNode;
		tmpNode = tmpNode->next;
	}

	/*make result struct*/
	if (result > RULE_RESULT_OK) {
		newNode = (PRULEOUT) malloc(sizeof(RULEOUT));
		if (pRuleHead == NULL ) {
			pRuleHead = newNode;
		}

		//TODO
		//codeScp = ??;
		newNode->indexInfo = index;
		newNode->fileIndex = CCodeScope.getFileIndex(codeScp);
		newNode->beginLine = CCodeScope.getBeginLine(codeScp);
		newNode->beginCol = CCodeScope.getBeginLineOffset(codeScp);
		newNode->endLine = CCodeScope.getEndLine(codeScp);
		newNode->endCol = CCodeScope.getEndLineOffset(codeScp);
		newNode->ruleID = RuleID;
		newNode->errRank = RANK;

		//TODO
		sprintf(newNode->msgBuf_eng, MESSAGE_ENG);
		sprintf(newNode->msgBuf_chs, MESSAGE_CHS);
		sprintf(newNode->msgBuf_jpn, MESSAGE_JPN);

		newNode->rfileIndex = 0;
		newNode->rlocLine = 0;
		newNode->next = NULL;

		if (pRuleTail != NULL ) {
			pRuleTail->next = newNode;
		}

		pRuleTail = newNode;
	}

	return EXIT_SUCCESS;
}

VOID C5_2_5_register(VOID) {
	PRULEMAN * pCurRule = &stRuleManager;
	PRULEMAN newRuleMan = (PRULEMAN) malloc(sizeof(RULEMAN));
	memset(newRuleMan, 0, sizeof(RULEMAN));
	newRuleMan->ruleID = RuleID;
	newRuleMan->ruleSwitch = OFF;
	newRuleMan->headOut = &pRuleHead;
	newRuleMan->tailOut = &pRuleTail;
	newRuleMan->ruleMain_ast = RuleMain;
	if (stRuleManager == NULL ) {
		stRuleManager = newRuleMan;
	} else {
		while ((*pCurRule)->nextRule != NULL ) {
			pCurRule = &((*pCurRule)->nextRule);
		}
		(*pCurRule)->nextRule = newRuleMan;
	}
}

static INT RuleCheck(U2 kind, AST index, U4 event, AST* pCodeScp) {
	INT result = RULE_RESULT_OK;

	AST astDefaultStat = 0;
	AST astNextStat = 0;

	if (kind != TR_KIND_STATEMENT) {
		return EXIT_SUCCESS;
	}

	if (!(event & EVT_STATEMENT)) {
		return EXIT_SUCCESS;
	}

	if (!CStatement.isSwitch(index)) {
		return EXIT_SUCCESS;
	}

	// there is no default in the switch ,return NG
	astDefaultStat = CStatement.switch_getDefault(index);
	if (astDefaultStat == 0) {
		*pCodeScp = CStatement.getCodeScope(index);
		return RULE_RESULT_NG;
	} else {
		// there is a default , but there is also a case after the default , return NG
		astNextStat = CStatement.getNextStmt(astDefaultStat);
		while (astNextStat != 0) {
			if (CStatement.isCase(astNextStat)) {
				*pCodeScp = CStatement.getCodeScope(astDefaultStat);
				return RULE_RESULT_NG;
			}
			astNextStat = CStatement.getNextStmt(astNextStat);
		}
	}

	return result;

}
